#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
实验标题：《桃花源记》词频统计实验 - 基于原生数据结构的轻量级自然语言处理

实验目标：
使用Python原生数据结构（列表和字典），不依赖任何第三方库，
完成对《桃花源记》文本的词频统计分析，展示基础数据结构在文本处理中的应用。

实验步骤：
1. 文本切分：使用标点符号将长文本切分成意群片段
2. 词语枚举：2-4字滑动窗口枚举所有可能的词语组合
3. 数据过滤：剔除包含标点或长度不符的无效组合
4. 频次统计：使用字典累加每个词语的出现次数
5. 结果排序：按频次倒序排列并输出高频词语

作者：做运维的阿瑞
日期：2024年
"""

def split_text_by_punctuation(text):
    """
    文本切分功能：使用常见标点符号将长文本切分成意群片段
    
    Args:
        text (str): 输入的原始文本
        
    Returns:
        list: 切分后的文本片段列表
    """
    # 定义常见的中文标点符号
    punctuations = ['。', '，', '；', '：', '！', '？', '、', '"', '"', ''', ''', '（', '）', '【', '】']
    
    # 初始化片段列表
    segments = []
    current_segment = ""
    
    for char in text:
        if char in punctuations:
            # 遇到标点符号，保存当前片段（如果非空）
            if current_segment.strip():
                segments.append(current_segment.strip())
            current_segment = ""
        else:
            # 非标点符号，添加到当前片段
            current_segment += char
    
    # 处理最后一个片段
    if current_segment.strip():
        segments.append(current_segment.strip())
    
    return segments


def enumerate_words_with_sliding_window(segment, min_len=2, max_len=4):
    """
    词语枚举功能：使用滑动窗口枚举指定长度范围内的所有词语组合
    
    Args:
        segment (str): 文本片段
        min_len (int): 最小词语长度，默认2
        max_len (int): 最大词语长度，默认4
        
    Returns:
        list: 枚举出的词语列表
    """
    words = []
    segment_len = len(segment)
    
    # 遍历每个可能的起始位置
    for start in range(segment_len):
        # 遍历每个可能的词语长度
        for length in range(min_len, max_len + 1):
            end = start + length
            if end <= segment_len:
                word = segment[start:end]
                words.append(word)
    
    return words


def filter_valid_words(words):
    """
    数据过滤功能：剔除包含标点符号或不符合要求的词语
    
    Args:
        words (list): 待过滤的词语列表
        
    Returns:
        list: 过滤后的有效词语列表
    """
    # 定义需要过滤的字符（标点符号、数字、英文等）
    invalid_chars = ['。', '，', '；', '：', '！', '？', '、', '"', '"', ''', ''', 
                    '（', '）', '【', '】', ' ', '\n', '\t', '\r']
    
    valid_words = []
    
    for word in words:
        # 检查词语是否包含无效字符
        is_valid = True
        for char in word:
            if char in invalid_chars or char.isdigit() or char.isascii():
                is_valid = False
                break
        
        # 检查词语长度是否符合要求（2-4字）
        if is_valid and 2 <= len(word) <= 4:
            valid_words.append(word)
    
    return valid_words


def count_word_frequency(words):
    """
    频次统计功能：使用字典统计每个词语的出现频次
    
    Args:
        words (list): 词语列表
        
    Returns:
        dict: 词语频次字典，格式为 {词语: 频次}
    """
    frequency_dict = {}
    
    for word in words:
        if word in frequency_dict:
            frequency_dict[word] += 1
        else:
            frequency_dict[word] = 1
    
    return frequency_dict


def sort_and_display_results(frequency_dict, top_n=20):
    """
    结果排序和输出功能：将频次字典转换为排序列表并输出
    
    Args:
        frequency_dict (dict): 词语频次字典
        top_n (int): 输出前N个高频词语，默认20
        
    Returns:
        list: 排序后的词语频次列表，格式为 [(词语, 频次), ...]
    """
    # 将字典转换为列表，每个元素为 (词语, 频次) 的元组
    frequency_list = []
    for word, count in frequency_dict.items():
        frequency_list.append((word, count))
    
    # 按频次进行倒序排序（使用冒泡排序展示原生算法）
    n = len(frequency_list)
    for i in range(n):
        for j in range(0, n - i - 1):
            if frequency_list[j][1] < frequency_list[j + 1][1]:
                # 交换位置
                frequency_list[j], frequency_list[j + 1] = frequency_list[j + 1], frequency_list[j]
    
    # 输出结果
    print(f"\n=== 《桃花源记》词频统计结果（前{top_n}名）===")
    print("-" * 50)
    print(f"{'排名':<4} {'词语':<8} {'频次':<6} {'占比':<8}")
    print("-" * 50)
    
    total_words = sum(count for _, count in frequency_list)
    
    for i in range(min(top_n, len(frequency_list))):
        word, count = frequency_list[i]
        percentage = (count / total_words) * 100
        print(f"{i+1:<4} {word:<8} {count:<6} {percentage:.2f}%")
    
    print("-" * 50)
    print(f"总词语数量: {len(frequency_list)}")
    print(f"总词频: {total_words}")
    
    return frequency_list


def main():
    """
    主函数：执行完整的词频统计实验流程
    """
    # 《桃花源记》原文（节选）
    peach_blossom_text = """
    晋太元中，武陵人捕鱼为业。缘溪行，忘路之远近。忽逢桃花林，夹岸数百步，
    中无杂树，芳草鲜美，落英缤纷。渔人甚异之，复前行，欲穷其林。
    林尽水源，便得一山，山有小口，仿佛若有光。便舍船，从口入。
    初极狭，才通人。复行数十步，豁然开朗。土地平旷，屋舍俨然，
    有良田美池桑竹之属。阡陌交通，鸡犬相闻。其中往来种作，男女衣着，
    悉如外人。黄发垂髫，并怡然自乐。见渔人，乃大惊，问所从来。
    具答之。便要还家，设酒杀鸡作食。村中闻有此人，咸来问讯。
    自云先世避秦时乱，率妻子邑人来此绝境，不复出焉，遂与外人间隔。
    问今是何世，乃不知有汉，无论魏晋。此人一一为具言所闻，皆叹惋。
    余人各复延至其家，皆出酒食。停数日，辞去。此中人语云：
    不足为外人道也。既出，得其船，便扶向路，处处志之。
    及郡下，诣太守，说如此。太守即遣人随其往，寻向所志，遂迷，不复得路。
    南阳刘子骥，高尚士也，闻之，欣然规往。未果，寻病终。后遂无问津者。
    """
    
    print("=== 《桃花源记》词频统计实验开始 ===")
    print(f"原文长度: {len(peach_blossom_text)} 字符")
    
    # 步骤1: 文本切分
    print("\n步骤1: 文本切分...")
    segments = split_text_by_punctuation(peach_blossom_text)
    print(f"切分得到 {len(segments)} 个文本片段")
    print("前5个片段示例:")
    for i, segment in enumerate(segments[:5]):
        print(f"  {i+1}. {segment}")
    
    # 步骤2: 词语枚举
    print("\n步骤2: 词语枚举...")
    all_words = []
    for segment in segments:
        words = enumerate_words_with_sliding_window(segment)
        all_words.extend(words)
    
    print(f"枚举得到 {len(all_words)} 个词语候选")
    print("前20个词语示例:")
    for i, word in enumerate(all_words[:20]):
        print(f"  {word}", end="  ")
        if (i + 1) % 10 == 0:
            print()  # 每10个换行
    
    # 步骤3: 数据过滤
    print("\n\n步骤3: 数据过滤...")
    valid_words = filter_valid_words(all_words)
    print(f"过滤后剩余 {len(valid_words)} 个有效词语")
    print(f"过滤率: {((len(all_words) - len(valid_words)) / len(all_words) * 100):.2f}%")
    
    # 步骤4: 频次统计
    print("\n步骤4: 频次统计...")
    frequency_dict = count_word_frequency(valid_words)
    print(f"统计得到 {len(frequency_dict)} 个不重复词语")
    
    # 步骤5: 结果排序和输出
    print("\n步骤5: 结果排序和输出...")
    sorted_results = sort_and_display_results(frequency_dict, top_n=15)
    
    # 额外分析
    print("\n=== 实验数据分析 ===")
    print(f"词语覆盖率: {(len(frequency_dict) / len(valid_words) * 100):.2f}%")
    
    # 统计不同频次的词语数量
    frequency_distribution = {}
    for word, count in frequency_dict.items():
        if count in frequency_distribution:
            frequency_distribution[count] += 1
        else:
            frequency_distribution[count] = 1
    
    print("\n频次分布:")
    for freq in sorted(frequency_distribution.keys(), reverse=True)[:10]:
        print(f"  出现{freq}次的词语: {frequency_distribution[freq]}个")
    
    print("\n=== 实验完成 ===")


if __name__ == "__main__":
    main()